#include "protocol.h"
#include "set_sok.h"
#include "exec.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 8016
#define IPV6_ADDR "::" // IPv6 equivalent of INADDR_ANY
#define LISTEN_NUM 128
#define MAX_CLIENT 16

/* 针对exec()函数的词法分析器  能够从exec()函数调用中提取出一个参数
 *
 * 需要注意的是，这个函数返回的字符串位于堆内存，最终需要释放。
 */
char *exec_lexer_only_one(char const *msg) {
	char *keyh = "exec{";
	char *keyt = "}";
	if (strstr(msg, keyh) != msg) {
		return NULL;
	}
	else {
		size_t all = strlen(msg);
		size_t head = strlen(keyh);
		size_t tail = strlen(keyt);
		size_t len = all - head - tail;
		char *path = (char *)malloc((len +1) * sizeof(char));
		if (!path) {
			perror("malloc");
			return NULL;
		}
		else {
			int i = 0;
			char *d = path;
			msg += head;
			for (;i < len;++i) {
				*(d++)= *(msg++);
			}
			*d = '\0';
			return path;
		}
	}
}

/* 处理执行请求，在受到执行请求后被调用 */
int handle_exec_request(int sockfd, int ret) {
	char *response = (ret) ? "ERR": "OK";
	if (qs_send(sockfd, response)) // 发送没成功
		return 1;
	return 0;
}
/* 处理列表请求，这个函数在收到列表请求后调用 */
int handle_list_request(int sockfd, char const *ls) {
	if (!qs_send(sockfd, ls))
		return 0;
	return 1;
}

int do_with_msg(int sockfd, char const *msg) {
	//printf("Client says: %s\n", msg);
	//
	char *path;
	if ((path = exec_lexer_only_one(msg))) {
		int ret = crt_p(path);
		handle_exec_request(sockfd, ret);
		return 0;
	} else if (!strcmp(msg, "list{}")) {	
		char *ls = p_list();
		if (ls) {
			handle_list_request(sockfd, ls);
			free(ls);
			return 0;
		}
	} 


	// 没有在分支中成功返回
	// 或者没有匹配到分支
	return 1;
}
int main() {
	int max_sd, activity;
	struct timeval timeout;
	fd_set read_fds;
	int server_fd;
	int new_socket;
	int client_sockets[MAX_CLIENT], i, sd;
	struct sockaddr_in6 address;
	int opt = 1;
	int addrlen = sizeof(address);

	// 初始化任务池
	ps_init();

	// 创建socket文件描述符
	if ((server_fd = socket(AF_INET6, SOCK_STREAM, 0)) == 0) {
		perror("socket failed");
		exit(EXIT_FAILURE);
	}

	// 设置socket选项
	if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
		perror("setsockopt");
		exit(EXIT_FAILURE);
	}

	// 设置非阻塞的套接字
	int flags = fcntl(sd, F_GETFL, 0);
	if (fcntl(server_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
		perror("fcntl");
		exit(EXIT_FAILURE);
	}

	address.sin6_family = AF_INET6;
	address.sin6_addr = in6addr_any;
	address.sin6_port = htons(PORT);

	// 绑定 socket 到端口
	if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
		perror("bind failed");
		exit(EXIT_FAILURE);
	}

	// 开始监听
	if (listen(server_fd, LISTEN_NUM) < 0) {
		perror("listen");
		exit(EXIT_FAILURE);
	}

	printf("Server listening on port %d...\n", PORT);

	// 初始化客户端socket数组
	for (i=0; i<MAX_CLIENT; ++i) {
		client_sockets[i] = 0;
	}

	while(1) {
		
		// 初始化文件描述符集合
		FD_ZERO(&read_fds);
		FD_SET(server_fd, &read_fds);
		max_sd = server_fd;

		// 添加所有有效的客户端socket到集合
		for (int i=0; i<MAX_CLIENT; ++i) {
			sd = client_sockets[i];
			if (sd > 0) {
				FD_SET(sd, &read_fds);
			}
			if (sd > max_sd) {
				max_sd = sd;
			}
		}
		
		// 设置超时时间
		// 不可以设置在循环之外，因为传递过一次之后会被清零
		timeout.tv_sec = 1;
		timeout.tv_usec= 10000;

		// 阻塞等待socket活动
		activity = select(max_sd + 1, &read_fds, NULL, NULL, &timeout);

		// 系统调用出错
		if (activity < 0 && errno != EINTR) {
			perror("select error");
			exit(EXIT_FAILURE);
		}

		// 超时
		if (activity == 0) {
			//printf("timeout\n");
			continue;
		}

		
		if (FD_ISSET(server_fd, &read_fds)) { // 有连接请求
			
			// 接受连接
			new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen);
			if (new_socket < 0) {
				perror("accept failed");
				exit(EXIT_FAILURE);
			}

			// 获取客户端IPv6地址并打印
			char client_ip[INET6_ADDRSTRLEN];
			inet_ntop(AF_INET6, &address.sin6_addr, client_ip, INET6_ADDRSTRLEN);
			printf("Connection from: %s\n", client_ip);

			// 将新的客户端socket加入数组
			for (i = 0; i <MAX_CLIENT; ++i) {
				if (client_sockets[i] == 0) {

					// 设置客户端套接字的阻塞时间
					if (set_block_timout(new_socket, 0, 10000)) { // 设置失败
						break;
					}

					// 纳入数组
					client_sockets[i] = new_socket;
					break;

				}
			}

			// 连接池爆了
			if (i == MAX_CLIENT) {
				printf("Too many clients, connection rejected.\n");
				close(new_socket);
				continue;
			}
		}


		// 处理所有客户端socket是否有数据可读
		for (i=0; i<MAX_CLIENT; ++i) {
			sd = client_sockets[i];
			if (sd >0 && FD_ISSET(sd, &read_fds)) {
			
				// 读取客户端信息，这里应使用有错误处理的接收方式
				char *msg = qs_recv(sd, QSONT_MAX_LEN);
				if (msg) {
					do_with_msg(sd, msg);
					free(msg);
				}
				// 通信完毕，关闭套接字
				close(sd);
				client_sockets[i] = 0;

			}
		}

	}
	close(server_fd);
	ps_free();
	wait_p(); // 等待子进程结束
	return 0;
}
